from utils import image_processing, rabbitmq_util, face_util, file_util, mongo_util, debug_util, dataset_util, response_util
from dao import face_res_dao, face_attendence_dao
from service import mongo_service
from align import align_dataset_mtcnn
import const
import os
import shutil
import datetime as dt

def verify_face(username, file_list):
    face_res = face_res_dao.select_by_stu_no(username)
    if face_res == None:
        return response_util.error('no verify auth')
    if face_res['status'] == 2 or face_res['status'] == 3:
        return response_util.error('no verify auth')
    image_path = const.OUTPUT_VERIFY_IMG_PATH + username + '/1/'
    file_util.no_exist_and_create(image_path)
    index = 1
    for item in file_list:
        file_name = str(index) + '_jpg'
        file_path = image_path + file_name
        item.save(file_path)
        index += 1
    # 加载数据库的数据
    dataset_emb = dataset_util.load_dataset(username)
    # 初始化mtcnn人脸检测
    face_detect = const.FACE_DETECT
    # 初始化facenet
    face_net = const.FACE_NET
    # 待验证的图片
    imgPathList = os.listdir(image_path)
    # 识别成功总数
    successCount = 0
    # 识别成功相似度总值
    successTotalScore = 0
    # 未知总数
    failCount = 0
    for itemPath in imgPathList:
        image = image_processing.read_image_gbk(image_path + itemPath)
        # 获取 判断标识 bounding_box crop_image
        bboxes, landmarks = face_detect.detect_face(image)
        bboxes, landmarks = face_detect.get_square_bboxes(bboxes, landmarks, fixed="height")
        if bboxes == [] or landmarks == []:
            debug_util.logger.warning('img[%s] no face')
            continue
        debug_util.logger.info('[%s] img[%s] have %d faces' % (username, itemPath, len(bboxes)))
        face_images = image_processing.get_bboxes_image(image, bboxes, const.RESIZE_HEIGHT, const.RESIZE_WIDTH)
        face_images = image_processing.get_prewhiten_images(face_images)
        pred_emb = face_net.get_embedding(face_images)  # 获取当前图片的特征向量
        pred_name, pred_score = face_util.compare_embedding(username, pred_emb, dataset_emb)  # 比较特征向量
        if pred_name[0] == 'unknow':
            failCount += 1
        if pred_name[0] == username:
            successCount += 1
            successTotalScore += float(pred_score[0])
        debug_util.logger.debug('name: %s, score: %s' % (pred_name, str(pred_score)))
    agv = 0
    if successCount != 0 and successTotalScore != 0:
        agv = '{:.3f}'.format(successTotalScore / successCount)
        debug_util.logger.info('成功总数: %s, 成功平均值: %s, 失败总数: %s' % (
            str(successCount), str(successTotalScore / successCount), str(failCount)))
    debug_util.logger.info('成功总数: %s, 成功平均值: %s, 失败总数: %s' % (str(successCount), str(0), str(failCount)))
    shutil.rmtree(image_path)
    if successCount == 0:
        return response_util.error('Validation failed')
    else:
        return response_util.success()

def upload_face_imgs(stu_info, file_list):
    username = stu_info['studentNo']
    class_id = stu_info['classId']
    face_res = face_res_dao.select_by_stu_no(username)
    if not face_res == None and not face_res['status'] == 2:
        return response_util.error('no input auth')
    image_name = file_util.generate_temp_img_filename(username)
    image_path = const.OUTPUT_TEMP_PATH + username + '/'
    file_util.no_exist_and_create(image_path)
    # delete the old imgs in MongoDB
    mongo_service.remove_file({
        'filename': image_name
    }, 'temp')
    index = 1
    for file in file_list:
        file_name = str(index) + '_jpg'
        file_path = image_path + file_name
        file.save(file_path)
        index += 1
    # delete the old record in MongoDB
    mongo_util.del_file({'filename':username}, 'temp')
    # upload images to MongoDB
    temp_image_list = os.listdir(image_path)
    for file in temp_image_list:
        temp_path = image_path + file
        mongo_util.upload_file(temp_path, image_name, 'temp')
    debug_util.logger.info('upload success')
    # push message to RabbitMQ
    param = {
        'queue': const.MQ.QUEUE_FACE_PY,
        'exchange': const.MQ.EXCAHNGE,
        'routing_key': const.MQ.QUEUE_FACE_PY,
        'durable': True
    }
    rabbitmq_util.send_message(param, {
        'action': const.ACTION.ALIGN_BUILD,
        'stu_no': username
    })
    # check the face res
    result = face_res_dao.select_by_stu_no(username)
    if result == None:
        # create new row
        face_res_dao.insert((username, class_id, 3, dt.datetime.now(), None, None))
    else:
        # update
        face_res_dao.update_status_by_stu_no((3, dt.datetime.now(), username))
    # delete temp images
    shutil.rmtree(image_path)
    return response_util.success()

def align_and_build(stu_no):
    filename = file_util.generate_temp_img_filename(stu_no)
    temp_img_root_path = const.INPUT_TRAIN_IMAGE_PATH + stu_no + '/'
    temp_img_save_path = temp_img_root_path + stu_no + '/'
    align_img_root_path = const.OUTPUT_TRAIN_IMG_PATH + stu_no + '/'
    align_img_save_path = align_img_root_path + stu_no + '/'
    file_util.no_exist_and_create(temp_img_save_path, align_img_save_path)
    # download the images
    mongo_service.download_temp_images(stu_no, filename, temp_img_save_path)
    # align images
    align_dataset_mtcnn.align_images(temp_img_root_path, align_img_root_path)
    # 将图片转成base64字符串 存入mongodb
    mongo_service.upload_align_images(stu_no, align_img_save_path)
    # 对已经预处理的图片进行提取特征向量操作
    npy_filename, npy_file_path, txt_filename, txt_file_path = face_util.create_embedding_file(stu_no, align_img_save_path)
    # upload file to MongoDB
    mongo_service.upload_embedding_file(npy_filename, npy_file_path, 'embbing', True)
    mongo_service.upload_embedding_file(txt_filename, txt_file_path, 'embbing', True)
    # delete the old embedding file
    file_util.delete_file(npy_file_path, txt_file_path)
    # change the face_res status
    face_res_dao.update_status_by_stu_no((0, dt.datetime.now(), stu_no))
    debug_util.info('input face success stuno:{}'.format(stu_no))
    # send msg to RabbitMQ
    rabbitmq_util.send_message({
        'queue': const.MQ.QUEUE_SHARED_FILE,
        'exchange': const.MQ.EXCAHNGE,
        'routing_key': const.MQ.QUEUE_SHARED_FILE,
        'durable': True
    }, {
        'stu_no': stu_no
    })
    return response_util.success()

def verify_face_res_for_android(stu_no, attendence_id, md5, threshold):
    # get threshold to MongoDB
    result = mongo_service.get_threshold({'name': 'threshold'}, 'setting')
    remote_threshold = result['threshold']
    threshold = float(threshold)
    if not remote_threshold == threshold:
        return response_util.error('Validation failed')
    # get txt file info to MongoDB
    filename = file_util.generate_txt_filename(stu_no)
    client, file_info = mongo_service.get_file_info(filename, 'embbing')
    if file_info == None:
        return response_util.error('Validation failed')
    if not file_info._file['md5'] == md5:
        return response_util.error('Validation failed')
    client.close()
    # Validation success
    result = None
    result = face_attendence_dao.select_by_attendenceid(attendence_id)
    # update the face_attendence
    row = face_attendence_dao.update(('Y', dt.datetime.now(), result['id']))
    if row == 0:
        return response_util.error('Validation failed')
    return response_util.success()

def get_embedding_for_android(stuno):
    # check the face_res state
    res = face_res_dao.select_by_stu_no(stuno)
    if res == None:
        raise Exception('no face auth')
    state = res['status']
    if state == 2 or state == 3 :
        return Exception('no face auth')
    # get mongoDB file info
    filename = stuno + const.TAG.SUFFIX_TXT
    client, file_info = mongo_service.get_file_info(filename, 'embbing')
    context = str(file_info.read(), encoding="utf-8")
    emdding_arr = context.split('\n')
    client.close()
    return emdding_arr
